-
Notifications
You must be signed in to change notification settings - Fork 292
Add option to exclude a field using a callable #1535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add option to exclude a field using a callable #1535
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅ 📢 Thoughts on this report? Let us know! |
please review |
CodSpeed Performance ReportMerging #1535 will not alter performanceComparing Summary
|
src/serializers/fields.rs
Outdated
serializer: &CombinedSerializer, | ||
) -> PyResult<bool> { | ||
let py = value.py(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
think this should be called only if any condition is met, right? inside the if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should probably handle this outside of the exclude_default
function as to decouple them for readability. We don't couple exclude_default
with exclude_none
or exclude_unset
, so I think we should retain separation here as well!
Super exciting! Will give this a thorough review soon. Working on getting v2.10 out, and this will be included in v2.11 :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would love to see an implementation on the pydantic
side as well - you can point to this branch.
Looks like a great start. I'm impressed with how simple this is going to be!
src/serializers/fields.rs
Outdated
serializer: &CombinedSerializer, | ||
) -> PyResult<bool> { | ||
let py = value.py(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should probably handle this outside of the exclude_default
function as to decouple them for readability. We don't couple exclude_default
with exclude_none
or exclude_unset
, so I think we should retain separation here as well!
I would anticipate that folks might want to set this at the |
Hello @sydney-runkle ! How do you do the implementation in |
I'm curious how the callable should work in the class Model(BaseModel):
foo: str
bar: list[str]
foobaz: int
>>> Model(foo = "", bar = [], foobaz = 1).model_dump(exclude_if = lambda field: not field)
{"foobaz": 1} |
Yes, exactly this! Once we merge, we'll include in a minor It's just helpful to see the implementation on both sides before we merge the |
Yes, exactly this. That being said, I chatted with the team, and we decided that introducing this at the field level first makes sense, and we can follow with other config / runtime specs later. |
d7d7d0e
to
b225197
Compare
Alright, @sydney-runkle I created a PR pointing to this branch! |
Any news on this? |
@sydney-runkle It sounds like this feature did not get out in v2.11? Any news on when it might come out? |
@@ -2817,7 +2817,8 @@ class TypedDictField(TypedDict, total=False): | |||
validation_alias: Union[str, List[Union[str, int]], List[List[Union[str, int]]]] | |||
serialization_alias: str | |||
serialization_exclude: bool # default: False | |||
metadata: Dict[str, Any] | |||
exclude_if: Callable[[Any], bool] # default None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if: Callable[[Any], bool] # default None | |
serialization_exclude_if: Callable[[Any], bool] # default None |
@@ -2827,7 +2828,8 @@ def typed_dict_field( | |||
validation_alias: str | list[str | int] | list[list[str | int]] | None = None, | |||
serialization_alias: str | None = None, | |||
serialization_exclude: bool | None = None, | |||
metadata: Dict[str, Any] | None = None, | |||
exclude_if: Callable[[Any], bool] | None = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if: Callable[[Any], bool] | None = None, | |
serialization_exclude_if: Callable[[Any], bool] | None = None, |
@@ -2844,6 +2846,7 @@ def typed_dict_field( | |||
validation_alias: The alias(es) to use to find the field in the validation data | |||
serialization_alias: The alias to use as a key when serializing | |||
serialization_exclude: Whether to exclude the field when serializing | |||
exclude_if: Callable that determines whether to exclude a field during serialization based on its value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if: Callable that determines whether to exclude a field during serialization based on its value. | |
serialization_exclude_if: A callable that determines whether to exclude the field when serializing based on its value. |
@@ -2853,6 +2856,7 @@ def typed_dict_field( | |||
validation_alias=validation_alias, | |||
serialization_alias=serialization_alias, | |||
serialization_exclude=serialization_exclude, | |||
exclude_if=exclude_if, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if=exclude_if, | |
serialization_exclude_if=serialization_exclude_if, |
@@ -2943,6 +2947,7 @@ class ModelField(TypedDict, total=False): | |||
validation_alias: Union[str, List[Union[str, int]], List[List[Union[str, int]]]] | |||
serialization_alias: str | |||
serialization_exclude: bool # default: False | |||
exclude_if: Callable[[Any], bool] # default: None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if: Callable[[Any], bool] # default: None | |
serialization_exclude_if: Callable[[Any], bool] # default: None |
@@ -3171,7 +3179,8 @@ class DataclassField(TypedDict, total=False): | |||
validation_alias: Union[str, List[Union[str, int]], List[List[Union[str, int]]]] | |||
serialization_alias: str | |||
serialization_exclude: bool # default: False | |||
metadata: Dict[str, Any] | |||
exclude_if: Callable[[Any], bool] # default: None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if: Callable[[Any], bool] # default: None | |
serialization_exclude_if: Callable[[Any], bool] # default: None |
@@ -3184,7 +3193,8 @@ def dataclass_field( | |||
validation_alias: str | list[str | int] | list[list[str | int]] | None = None, | |||
serialization_alias: str | None = None, | |||
serialization_exclude: bool | None = None, | |||
metadata: Dict[str, Any] | None = None, | |||
exclude_if: Callable[[Any], bool] | None = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if: Callable[[Any], bool] | None = None, | |
serialization_exclude_if: Callable[[Any], bool] | None = None, |
@@ -3210,6 +3220,7 @@ def dataclass_field( | |||
validation_alias: The alias(es) to use to find the field in the validation data | |||
serialization_alias: The alias to use as a key when serializing | |||
serialization_exclude: Whether to exclude the field when serializing | |||
exclude_if: Callable that determines whether to exclude a field during serialization based on its value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if: Callable that determines whether to exclude a field during serialization based on its value. | |
serialization_exclude_if: A callable that determines whether to exclude the field when serializing based on its value. |
@@ -3223,6 +3234,7 @@ def dataclass_field( | |||
validation_alias=validation_alias, | |||
serialization_alias=serialization_alias, | |||
serialization_exclude=serialization_exclude, | |||
exclude_if=exclude_if, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exclude_if=exclude_if, | |
serialization_exclude_if=serialization_exclude_if, |
@@ -80,6 +95,7 @@ fn exclude_default(value: &Bound<'_, PyAny>, extra: &Extra, serializer: &Combine | |||
} | |||
} | |||
} | |||
// If neither condition is met, do not exclude the field |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets avoid diff noise:
// If neither condition is met, do not exclude the field |
Change Summary
This PR aims to add support for excluding field from serialization based on condition. As @davidhewitt suggested I added a new
exclude_if
argument at field level, which is callable that checks if the field value meets a condition. However, in this pydantic issue David suggested to useskip_serializing_if
from Rust's serde, I could't find a way to use it due that serialization is being doing a loop for each field usingserialize_map
.Related issue number
pydantic/pydantic#10728
Checklist
pydantic-core
(except for expected changes)Selected Reviewer: @sydney-runkle